package android.gpstrac.controls.providers;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.gpstrac.data.User;
import android.gpstrac.data.UserLocation.UserLocationContent;
import android.gpstrac.data.User.UserContent;
import android.net.Uri;
import java.util.HashMap;


/**
 * Provides access to the data used in the GPSTrac application.
 *
 * @author Nicolas Papin
 */
public class GPSTracContentProvider extends ContentProvider
{
	//
	// CLASS AND INSTANCE DATA
	//
	/**
	 * The name of the internal database in this content provider.
	 */
	private static final String DB_NAME = "gpstrac.db";
	
	/**
	 * Version number to be changed upon database update.
	 */
	private static final int DB_VERSION = 1;
	
	/**
	 * Authority for this database.
	 */
	public static final String AUTHORITY = "android.gpstrac.controls.providers.GPSTracContentProvider";
	
	/**
	 * URI Matcher
	 */
	private static final UriMatcher mUriMatch;
	
	/**
	 * Keys for URI Matching
	 */
	private static final int FRIEND_URI = 1;
	private static final int LOC_URI = 2;
	
	/**
	 * Projections to use for describing the database accesses.
	 */
	private static HashMap<String, String> mFriendProjection;
	private static HashMap<String, String> mLocProjection;

	/**
	 * Helper used for accessing the database.
	 */
	private GPSTracDBHelper mDBHelper;
	
	//
	// METHODS
	//	
	/* (non-Javadoc)
	 * @see android.content.ContentProvider#delete(android.net.Uri, java.lang.String, java.lang.String[])
	 */
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs)
	{
		SQLiteDatabase db = mDBHelper.getWritableDatabase();
		int count;
		
		switch(mUriMatch.match(uri))
		{
			case FRIEND_URI:
				count = db.delete(UserContent.TABLE_NAME, selection, selectionArgs);
				break;
			case LOC_URI:
				count = db.delete(UserLocationContent.TABLE_NAME, selection, selectionArgs);
				break;
			default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
	
	/* (non-Javadoc)
	 * @see android.content.ContentProvider#getType(android.net.Uri)
	 */
	@Override
	public String getType(Uri uri)
	{
		switch(mUriMatch.match(uri))
		{
			case FRIEND_URI:
				return UserContent.CONTENT_TYPE;
			case LOC_URI:
				return UserLocationContent.CONTENT_TYPE;
			default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
		}
	}
	
	/* (non-Javadoc)
	 * @see android.content.ContentProvider#insert(android.net.Uri, android.content.ContentValues)
	 */
	@Override
	public Uri insert(Uri uri, ContentValues values)
	{
		SQLiteDatabase db = mDBHelper.getWritableDatabase();
		long rowId = 0;
		
		switch(mUriMatch.match(uri))
		{
			case FRIEND_URI:
				rowId = db.insert(UserContent.TABLE_NAME, null, values);
				break;
			case LOC_URI:
				rowId = db.insert(UserLocationContent.TABLE_NAME, null, values);
				break;
			default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		
		if(rowId > 0)
		{
			Uri newUri = ContentUris.withAppendedId(uri, rowId);
			getContext().getContentResolver().notifyChange(newUri, null);
			return newUri;
		}
		
		return null;
	}
	
	/* (non-Javadoc)
	 * @see android.content.ContentProvider#onCreate()
	 */
	@Override
	public boolean onCreate()
	{
		mDBHelper = new GPSTracDBHelper(getContext());
		if(mDBHelper == null)
			return false;
		else
			return true;
	}
	
	/* (non-Javadoc)
	 * @see android.content.ContentProvider#query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String)
	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
	{
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		SQLiteDatabase db = mDBHelper.getReadableDatabase();
		
		switch(mUriMatch.match(uri))
		{
			case FRIEND_URI:
				qb.setTables(UserContent.TABLE_NAME);
				qb.setProjectionMap(mFriendProjection);
				break;
			case LOC_URI:
				qb.setTables(UserLocationContent.TABLE_NAME);
				qb.setProjectionMap(mLocProjection);
				break;
			default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		
		Cursor cur = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);
		cur.setNotificationUri(getContext().getContentResolver(), uri);

		return cur;
	}
	
	/* (non-Javadoc)
	 * @see android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[])
	 */
	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
	{
		SQLiteDatabase db = mDBHelper.getWritableDatabase();
		int count;
		
		switch(mUriMatch.match(uri))
		{
			case FRIEND_URI:
				count = db.update(UserContent.TABLE_NAME, values, selection, selectionArgs);
				break;
			case LOC_URI:
				count = db.update(UserLocationContent.TABLE_NAME, values, selection, selectionArgs);
				break;
			default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		
		getContext().getContentResolver().notifyChange(uri, null);
		
		return count;
	}
	
	//
	// INITIALIZATION
	//
	static 
	{
		mUriMatch = new UriMatcher(UriMatcher.NO_MATCH);
		mUriMatch.addURI(AUTHORITY, UserContent.TABLE_NAME, FRIEND_URI);
		mUriMatch.addURI(AUTHORITY, UserLocationContent.TABLE_NAME, LOC_URI);
		
		mFriendProjection = new HashMap<String, String>();
		mFriendProjection.put(UserContent.USER_ID, UserContent.USER_ID);
		mFriendProjection.put(UserContent.NAME, UserContent.NAME);
		
		mLocProjection = new HashMap<String, String>();
		mLocProjection.put(UserLocationContent.LOC_ID, UserLocationContent.LOC_ID);
		mLocProjection.put(UserLocationContent.USER, UserLocationContent.USER);
		mLocProjection.put(UserLocationContent.LAT, UserLocationContent.LAT);
		mLocProjection.put(UserLocationContent.LONG, UserLocationContent.LONG);
		mLocProjection.put(UserLocationContent.SEQ, UserLocationContent.SEQ);
	}
	
	//
	// UTILIZED CLASSES
	//
	private static class GPSTracDBHelper extends SQLiteOpenHelper
	{
		public GPSTracDBHelper(Context context)
		{
			super(context, DB_NAME, null, DB_VERSION);
		}

		/* (non-Javadoc)
		 * @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase)
		 */
		@Override
		public void onCreate(SQLiteDatabase db)
		{
			db.execSQL("CREATE TABLE " + UserContent.TABLE_NAME + " (" +
						UserContent.USER_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
						UserContent.NAME + " VARCHAR(" + User.USER_ID_LEN + ") UNIQUE);");
			
			db.execSQL("CREATE TABLE " + UserLocationContent.TABLE_NAME + " (" +
						UserLocationContent.LOC_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
						UserLocationContent.USER + " VARCHAR(" + User.USER_ID_LEN + ")," +
						UserLocationContent.LAT + " REAL," +
						UserLocationContent.LONG + " REAL," +
						UserLocationContent.SEQ + " INTEGER," +
						"FOREIGN KEY(" + UserLocationContent.USER + ") REFERENCES " + UserContent.TABLE_NAME + "(" + UserContent.NAME + "));");
		}

		/* (non-Javadoc)
		 * @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
		 */
		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
		{
			db.execSQL("DROP TABLE IF EXISTS " + UserContent.TABLE_NAME + ";");
			db.execSQL("DROP TABLE IF EXISTS " + UserLocationContent.TABLE_NAME + ";");
			onCreate(db);
		}
	}
}
